package com.william.jdbcplus.core.dao.impl;

import com.william.jdbcplus.common.entity.Entity;
import com.william.jdbcplus.common.page.IPage;
import com.william.jdbcplus.common.page.Page;
import com.william.jdbcplus.core.crud.CrudConfig;
import com.william.jdbcplus.core.crud.IBaseCrud;
import com.william.jdbcplus.core.dao.IBaseDao;
import com.william.jdbcplus.core.meta.TableHelperUtil;
import com.william.jdbcplus.core.query.EntityWrap;
import com.william.jdbcplus.core.query.UpdateWrap;
import com.william.jdbcplus.core.toolkit.Wrappers;
import com.william.jdbcplus.core.toolkit.string.StringTool;

import java.util.*;

/**
 * 基类实现
 *
 * @author william
 */
public class BaseDaoImpl implements IBaseDao {
    protected final CrudConfig dbConfig;
    protected final IBaseCrud baseCrud;

    public BaseDaoImpl(CrudConfig dbConfig, IBaseCrud baseCrud) {
        this.dbConfig = dbConfig;
        this.baseCrud = baseCrud;
    }

    /**
     * 主键值
     */
    protected <M extends Entity> Object getPkVal(M entity) {
        if (entity == null) {
            return null;
        }
        return TableHelperUtil.getEntityIdVal(entity);
    }

    /**
     * 判断数据库操作是否成功
     *
     * @return boolean
     */
    protected boolean retBool(Integer result) {
        return result != null && result > 0;
    }

    protected <M> M getObject(List<M> list) {
        if (list == null || list.size() == 0) {
            return null;
        } else {
            return list.get(0);
        }
    }

    protected <M extends Entity> EntityWrap<M> getEmptyWrap(Class<M> entityClass) {
        return Wrappers.entityWrap(entityClass);
    }

    @Override
    public <M extends Entity> String add(M entity) {
        if (entity == null) {
            return null;
        }

        String id = baseCrud.insert(entity, dbConfig);
        return id;
    }

    /**
     * TableId 注解存在更新记录，否插入一条记录
     *
     * @param entity 实体对象
     * @return boolean
     */
    @Override
    public <M extends Entity> boolean addOrUpdate(M entity) {
        if (entity == null) {
            return false;
        }
        Object pk = getPkVal(entity);
        if (StringTool.checkValNull(pk)) {
            add(entity);
            return true;
        } else {
            M oldEntity = getById(pk.toString(), TableHelperUtil.getEntityClass(entity));
            if (oldEntity == null) {
                add(entity);
                return true;
            } else {
                return updateById(entity);
            }
        }
    }

    @Override
    public <M extends Entity> boolean addOrUpdateList(Collection<M> entityList) {
        if (entityList == null || entityList.size() == 0) {
            return false;
        }
        for (M entity : entityList) {
            addOrUpdate(entity);
        }

        return true;
    }

    @Override
    public <M extends Entity> boolean copyList(List<M> entityList) {
        if (entityList == null || entityList.size() == 0) {
            return false;
        }

        baseCrud.copyList(entityList, dbConfig);
        return true;
    }

    @Override
    public <M extends Entity> boolean addList(List<M> entityList) {
        if (entityList == null || entityList.size() == 0) {
            return false;
        }

        baseCrud.insertList(entityList, dbConfig);
        return true;
    }

    @Override
    public <M extends Entity> boolean updateById(String id, UpdateWrap<M> updateWrap) {
        Class<M> entityClass = updateWrap.getEntityClass();

        EntityWrap<M> wrap = Wrappers.entityWrap(entityClass);
        wrap.eq(TableHelperUtil.getEntityIdFiledName(entityClass), id);

        return update(updateWrap, wrap);
    }

    @Override
    public <M extends Entity> boolean updateById(M entity) {
        if (entity == null) {
            return false;
        }

        // 如果主键值为空，直接返回错误
        Object pk = getPkVal(entity);
        if (StringTool.checkValNull(pk)) {
            return false;
        }

        // 获取更新字段列表
        Map<String, Object> columnMap = new HashMap<>();
        Map<String, Object> attrMap = TableHelperUtil.getEntityAttrMapWithoutLogicDelete(entity);
        for (Map.Entry<String, Object> attr : attrMap.entrySet()) {
            if (attr.getValue() != null) {
                columnMap.put(attr.getKey(), attr.getValue());
            }
        }

        EntityWrap<M> wrapper = Wrappers.entityWrap(TableHelperUtil.getEntityClass(entity));
        // 根据主键进行更新
        String pkField = TableHelperUtil.getEntityIdFiledName(TableHelperUtil.getEntityClass(entity));
        wrapper.eq(pkField, pk);
        columnMap.remove(pkField);

        // 如果更新字段数据为0，则无需更新
        if (columnMap.size() == 0) {
            return true;
        }

        //根据条件更新
        return updateByMap(columnMap, wrapper);
    }

    @Override
    public <M extends Entity> boolean update(M entity, EntityWrap<M> wrap) {
        if (entity == null) {
            return false;
        }

        // 获取更新字段列表
        Map<String, Object> columnMap = new HashMap<>();
        Map<String, Object> attrMap = TableHelperUtil.getEntityAttrMapWithoutLogicDelete(entity);
        for (Map.Entry<String, Object> attr : attrMap.entrySet()) {
            if (attr.getValue() != null) {
                columnMap.put(attr.getKey(), attr.getValue());
            }
        }
        String pkField = TableHelperUtil.getEntityIdFiledName(TableHelperUtil.getEntityClass(entity));
        columnMap.remove(pkField);

        // 如果更新字段数据为0，则无需更新
        if (columnMap.size() == 0) {
            return false;
        }

        //根据条件更新
        return updateByMap(columnMap, wrap);
    }

    @Override
    public <M extends Entity> boolean update(UpdateWrap<M> updateWrap, EntityWrap<M> entityWrap) {
        return updateByMap(updateWrap.getUpdateMap(), entityWrap);
    }

    @Override
    public <M extends Entity> boolean updateByMap(Map<String, Object> columnMap, EntityWrap<M> wrap) {
        if (columnMap == null || columnMap.size() == 0 || wrap == null) {
            return false;
        }

        return retBool(baseCrud.update(columnMap, wrap, dbConfig));
    }

    @Override
    public <M extends Entity> boolean updateList(Collection<M> entityList) {
        if (entityList == null || entityList.size() == 0) {
            return false;
        }
        for (M entity : entityList) {
            updateAll(entity);
        }
        return true;
    }

    @Override
    public <M extends Entity> boolean updateAll(M entity) {
        if (entity == null) {
            return false;
        }

        // 如果主键值为空，直接返回错误
        Object pk = getPkVal(entity);
        if (StringTool.checkValNull(pk)) {
            return false;
        }

        // 获取除逻辑删除字段外所有的字段
        Map<String, Object> attrMap = TableHelperUtil.getEntityAttrMapWithoutLogicDelete(entity);
        EntityWrap<M> wrapper = Wrappers.entityWrap(TableHelperUtil.getEntityClass(entity));
        // 根据主键进行更新
        String pkField = TableHelperUtil.getEntityIdFiledName(TableHelperUtil.getEntityClass(entity));
        wrapper.eq(pkField, pk);
        //删除主键，无需更新
        attrMap.remove(pkField);

        // 如果更新字段数据为0，则无需更新
        if (attrMap.size() == 0) {
            return true;
        }

        return updateByMap(attrMap, wrapper);
    }

    @Override
    public <M extends Entity> boolean deleteById(String pk, Class<M> entityClass) {
        if (pk == null || entityClass == null) {
            return false;
        }
        // 根据主键进行删除
        EntityWrap<M> wrapper = Wrappers.entityWrap(entityClass);
        wrapper.eq(TableHelperUtil.getEntityIdFiledName(entityClass), pk);
        return delete(wrapper);
    }

    @Override
    public <M extends Entity> boolean deleteByIds(Collection<String> ids, Class<M> entityClass) {
        if (ids == null || ids.size() == 0 || entityClass == null) {
            return false;
        }

        if (ids.size() > 0) {
            EntityWrap<M> wrapper = Wrappers.entityWrap(entityClass);
            wrapper.in(TableHelperUtil.getEntityIdFiledName(entityClass), ids);
            return delete(wrapper);
        }
        return true;
    }

    @Override
    public <M extends Entity> boolean delete(EntityWrap<M> wrap) {
        if (wrap == null) {
            return false;
        }

        if (wrap.isLogicDelete()) {
            return retBool(baseCrud.deleteLogic(wrap, dbConfig));
        } else {
            return retBool(baseCrud.deleteReal(wrap, dbConfig));
        }
    }

    @Override
    public <M extends Entity> boolean deleteAll(Class<M> entityClass) {
        if (entityClass == null) {
            return false;
        }
        return delete(getEmptyWrap(entityClass));
    }

    @Override
    public <M extends Entity> boolean realDelById(String pk, Class<M> entityClass) {
        if (pk == null || entityClass == null) {
            return false;
        }
        EntityWrap<M> wrapper = Wrappers.entityWrap(entityClass);
        wrapper.eq(TableHelperUtil.getEntityIdFiledName(entityClass), pk);
        return realDel(wrapper);
    }

    @Override
    public <M extends Entity> boolean realDelByIds(Collection<String> ids, Class<M> entityClass) {
        if (ids == null || ids.size() == 0 || entityClass == null) {
            return false;
        }

        if (ids.size() > 0) {
            EntityWrap<M> wrapper = Wrappers.entityWrap(entityClass);
            wrapper.in(TableHelperUtil.getEntityIdFiledName(entityClass), ids);
            return realDel(wrapper);
        }
        return true;
    }

    @Override
    public <M extends Entity> boolean realDel(EntityWrap<M> wrap) {
        if (wrap == null) {
            return false;
        }

        return retBool(baseCrud.deleteReal(wrap, dbConfig));
    }

    @Override
    public <M extends Entity> boolean realDelAll(Class<M> entityClass) {
        if (entityClass == null) {
            return false;
        }
        return realDel(getEmptyWrap(entityClass));
    }

    @Override
    public <M extends Entity> M getById(String pk, Class<M> entityClass) {
        if (pk == null || entityClass == null) {
            return null;
        }
        EntityWrap<M> wrapper = Wrappers.entityWrap(entityClass);
        wrapper.eq(TableHelperUtil.getEntityIdFiledName(entityClass), pk);
        return get(wrapper);
    }

    @Override
    public <M extends Entity> M get(EntityWrap<M> wrap) {
        if (wrap == null) {
            return null;
        }

        if (wrap.isLogicDelete()) {
            // 设置逻辑删除条件
            wrap.setLogicCondition();
        }
        List<M> entityList = baseCrud.selectList(wrap, dbConfig);
        return getObject(entityList);
    }

    @Override
    public <M extends Entity> boolean exists(String id, Class<M> entityClass) {
        if (id == null || entityClass == null) {
            return false;
        }
        return getById(id, entityClass) != null;
    }

    @Override
    public <M extends Entity> boolean exists(EntityWrap<M> wrap) {
        if (wrap == null) {
            return false;
        }
        return count(wrap) > 0;
    }

    @Override
    public <M extends Entity> int countAll(Class<M> entityClass) {
        if (entityClass == null) {
            return 0;
        }
        return count(getEmptyWrap(entityClass));
    }

    @Override
    public <M extends Entity> int count(EntityWrap<M> wrap) {
        if (wrap == null) {
            return 0;
        }

        if (wrap.isLogicDelete()) {
            // 设置逻辑删除条件
            wrap.setLogicCondition();
        }

        return baseCrud.selectCount(wrap, dbConfig);
    }

    @Override
    public <M extends Entity> List<M> listAll(Class<M> entityClass) {
        if (entityClass == null) {
            return new ArrayList<M>();
        }
        return list(getEmptyWrap(entityClass));
    }

    @Override
    public <M extends Entity> List<M> list(EntityWrap<M> wrap) {
        if (wrap == null) {
            return new ArrayList<M>();
        }

        if (wrap.isLogicDelete()) {
            // 设置逻辑删除条件
            wrap.setLogicCondition();
        }
        List<M> entityList = baseCrud.selectList(wrap, dbConfig);
        return entityList;
    }

    @Override
    public <M extends Entity> IPage<M> page(IPage<?> page, EntityWrap<M> wrap) {
        if (wrap == null) {
            return new Page<M>();
        }

        if (wrap.isLogicDelete()) {
            // 设置逻辑删除条件
            wrap.setLogicCondition();
        }
        IPage<M> pager = baseCrud.selectPage(page, wrap, dbConfig);
        return pager;
    }

    @Override
    public <M extends Entity> List<M> listByIds(Collection<?> idList, Class<M> entityClass) {
        if (idList == null || entityClass == null) {
            return new ArrayList<M>();
        }
        if (idList.size() <= 0) {
            return new ArrayList<>();
        } else {
            EntityWrap<M> wrapper = Wrappers.entityWrap(entityClass);
            wrapper.in(TableHelperUtil.getEntityIdFiledName(entityClass), idList);
            if (wrapper.isLogicDelete()) {
                // 设置逻辑删除条件
                wrapper.setLogicCondition();
            }
            return baseCrud.selectList(wrapper, dbConfig);
        }
    }
}
